﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using ZYLFramework.Manage;
using Debug = UnityEngine.Debug;

public class BaseComp
{
}

public class PosComp:BaseComp
{
    public Vector3 Pos;
}

public class ColorComp:BaseComp
{
    public Color Color;
}

public class RotateComp:BaseComp
{
    public Vector3 Rotate;
}

public class GameObjectComp:BaseComp
{
    public GameObject go;
}

public abstract class BaseSystem
{
    public List<Type> CompList;
    public virtual void Start()
    {
        
    }

    public virtual void Update(List<BaseEntity> entities)
    {
        
    }
}

public class ShowSystem:BaseSystem
{
    public ShowSystem()
    {
        CompList = new List<Type>();
        CompList.Add(typeof(PosComp));
        CompList.Add(typeof(ColorComp));
        CompList.Add(typeof(RotateComp));
        CompList.Add(typeof(GameObjectComp));
    }
    public override void Update(List<BaseEntity> entities)
    {
        foreach (var entity in entities)
        {
            var posComp = entity.CompDict[typeof(PosComp)] as PosComp;
            var colorComp = entity.CompDict[typeof(ColorComp)]as ColorComp;
            var rotateComp = entity.CompDict[typeof(RotateComp)]as RotateComp;
            var gameObjectComp = entity.CompDict[typeof(GameObjectComp)]as GameObjectComp;

            var transform = gameObjectComp.go.transform;
            transform.position = posComp.Pos;
            transform.Rotate(rotateComp.Rotate);
            transform.gameObject.GetComponent<MeshRenderer>().material.color = colorComp.Color;
        }  
    }
}

public class BaseEntity
{
    public int Eid;
    public Dictionary<Type, BaseComp> CompDict;

    public BaseEntity()
    {
        CompDict = new Dictionary<Type, BaseComp>();
    }
}


public class EntityManage
{
    public Dictionary<int,BaseEntity> Entity;
    public static int Eid;

    public void Init()
    {
        Eid = 0;
        Entity = new Dictionary<int, BaseEntity>();
    }
    
    public int GetEid()
    {
        var id = Eid;
        Eid++;
        return id;
    }
    
    public int NewEntity(params Type[] types)
    {
        var id = AddEntity();
        foreach (var type in types)
        {
            AddComp(id, type);
        }
        return id;
    }
    
    public int AddEntity()
    {
        var id = GetEid();
        var entity = new BaseEntity
        {
            Eid = id
        };
        if (Entity.ContainsKey(id))
        {
            Entity.Remove(id);
        }
        Entity.Add(id,entity);
        return id;
    }
    
    public List<BaseEntity> GetEntityList(List<Type> types)
    {
        List<BaseEntity> baseEntities = new List<BaseEntity>();
        foreach (var v in Entity)
        {
            var flag = true;
            foreach (var type in types)
            {
                flag = flag && v.Value.CompDict.ContainsKey(type);
            }

            if (flag)
            {
               baseEntities.Add(v.Value); 
            }
        }

        return baseEntities;
    }
    
    public void DestroyEntity(int eId)
    {
        var entity = GetEntity(eId);
        if (entity == null)
        {
            return;
        }
        foreach (var v in entity.CompDict)
        {
            RemoveComp(eId,v.Key);
        }
        Entity.Remove(eId);
    }
    
    public bool CheckHasComp(int eId,params Type[] types)
    {
        if (!Entity.ContainsKey(eId))
        {
            return false;
        }
        var entity = Entity[eId];
        foreach (var type in types)
        {
            if (!entity.CompDict.ContainsKey(type))
            {
                return false;
            }
        }
        return true;
    }
    
    public BaseEntity GetEntity(int eId)
    {
        if (!Entity.ContainsKey(eId))
        {
            Debug.LogError($"{eId} not find in Entity");
            return null;
        }
        return Entity[eId];
    }
    
    public BaseComp GetComps(int eId,Type type)
    {
        var entity = GetEntity(eId);
        if (entity == null || !entity.CompDict.ContainsKey(type))
        {
            return null;
        }

        return entity.CompDict[type];
    }
    
    public void AddComp(int eId,Type type)
    {
        var entity = GetEntity(eId);
        if (entity == null)
        {
            return;
        }
        var comp = Activator.CreateInstance(type) as BaseComp;
        if (!entity.CompDict.ContainsKey(type))
        {
            entity.CompDict.Add(type,comp);
        }
        entity.CompDict[type] = comp;
    }
    
    public void RemoveComp(int eId,Type type)
    {
        var entity = GetEntity(eId);
        if (entity == null || !entity.CompDict.ContainsKey(type))
        {
            return;
        }
        entity.CompDict.Remove(type);
    }
}

public class World : MonoBehaviour
{
    public List<BaseSystem> Systems;
    public List<int> Entity;
    public EntityManage EntityManage;
    private void Awake()
    {
        EntityManage = new EntityManage();
        Systems = new List<BaseSystem>();
        Entity = new List<int>();
        EntityManage.Init();
        Systems.Add(new ShowSystem());
    }

    private void Start()
    {
        var go = Resources.Load("Prefabs/Cube") as GameObject;
        for (int i = 0; i < 100; i++)
        {
            for (int j = 0; j < 100; j++)
            {
                var eid = EntityManage.NewEntity(
                    typeof(PosComp),
                    typeof(ColorComp),
                    typeof(RotateComp),
                    typeof(GameObjectComp));
                Entity.Add(eid);
                var entity = EntityManage.GetEntity(eid);
                var posComp = entity.CompDict[typeof(PosComp)] as PosComp;
                var colorComp = entity.CompDict[typeof(ColorComp)] as ColorComp;
                var rotateComp = entity.CompDict[typeof(RotateComp)] as RotateComp;
                var gameObjectComp = entity.CompDict[typeof(GameObjectComp)] as GameObjectComp;
                posComp.Pos = new Vector3(i * 2, 0, j * 2);
                colorComp.Color = j % 2 == 0 ? Color.yellow : Color.red;
                rotateComp.Rotate = Vector3.up; 
                gameObjectComp.go = Instantiate(go);
            }
        }
    }

    private void Update()
    {
        foreach (var sys in Systems)
        {
           sys.Update(EntityManage.GetEntityList(sys.CompList)); 
        }
    }
}
